# coding: utf-8

import sys
import string
import random

# coding: utf-8

import os
from osgeo import ogr
from osgeo import osr
ogr.UseExceptions()


class PyOGRException(Exception):
    pass

    
def driver_by_name(name):
    driver = ogr.GetDriverByName(name)
    if driver is None:
        raise PyOGRException("Cannot create driver for %s" % name)
    return driver

    
def is_available(name):
    return any(name == driver.GetName() for driver in iterate_driver())
    
    
def iterate_driver():
    for index in xrange(ogr.GetDriverCount()):
        yield ogr.GetDriver(index)
    
    
def create_virtual_datasource(datasource):
    """
    creates a virtual datasource from the input datasource
    avoid changes to input datasource
    """
    
    memory_driver = ogr.GetDriverByName('Memory')
    virtual_datasource = memory_driver.CreateDataSource('')
    
    for layer in iterate_layers(datasource):
        virtual_datasource.CopyLayer(layer, layer.GetName())
    
    datasource.Release()
    
    return virtual_datasource
    
    
def create_srs_from_id(epsg_id):
    """create a spatial reference object from a EPSG ID"""
    srs = osr.SpatialReference()
    srs.ImportFromEPSG(epsg_id)
    return srs

    
def transform_feature_geometry(feature, transformation):
    pass
    
    
def create_datasource(driver, resource, **kwargs):
    ogr_datasource = driver.CreateDataSource(resource, **kwargs)
    if ogr_datasource is None:
        raise PyOGRException(u"Could not create datasource")
    return ogr_datasource

    
def open_datasource(driver, resource, update=False):
    """returns a OGRDatasource Object"""
    ogr_datasource = driver.Open(resource, update)
    if ogr_datasource is None:
        raise PyOGRException(u"Could not open datasource with driver")
    return ogr_datasource
    
    
def iterate_layers(datasource):
    for index in xrange(datasource.GetLayerCount()):
        yield datasource.GetLayer(index)

        
def iterate_features(layer):
    """
    using GetNextFeature is more effective than using GetFeature
    layer.GetNextFeature() returns None if there is no feature left
    
    for feature in iter(layer.GetNextFeature, None):
        yield feature
    layer.ResetReading() raises
    RuntimeError: Pointer 'hOtherFeat' is NULL in 'OGR_F_Equal'.
    """
    feature = layer.GetNextFeature()
    while feature:
        yield feature
        feature = layer.GetNextFeature()
    layer.ResetReading()
    
    
def iterate_e(feature):
    """iterator for fields in a feature"""
    
    for index in xrange(feature.GetFieldCount()):
        field = feature.GetFieldDefnRef(index)
        
        key = field.GetNameRef()
        field_type = field.GetType()
        value = feature.GetField(index)
        
        # yield (key, value)
        yield field
    
    
def get_geometry_type(layer):
    """get the geometry type of the layer
    """
    try:
        feature = iterate_features(layer).next()
        layer.ResetReading()
    except StopIteration:
        return None
    else:
        return feature.GetGeometryRef().GetGeometryType()
        
        
def create_layer(source_layer,layer_name, source_srs, target_datasource):
    """create a new layer from source layer with source srs on the
    target datasource. copy field definition from source layer and create fields
    on target layer"""
    
    geometry_type = get_geometry_type(source_layer)
    target_layer = target_datasource.CreateLayer(layer_name, source_srs,
                                                 geometry_type)
                                                 
    # copy field definition
    feature_definition = source_layer.GetLayerDefn()
    for index in xrange(feature_definition.GetFieldCount()):
        target_layer.CreateField(feature_definition.GetFieldDefn(index))
        
    return target_layer
    
    
def create_feature(source_feature, target_feature_definition, transformation):
    """create a new target feature from source feature"""
    
    target_feature = ogr.Feature(target_feature_definition)
    target_feature.SetFrom(source_feature)
    target_feature.SetFID(source_feature.GetFID())
    
    if transformation is not None:
        geometry_reference = source_feature.GetGeometryRef()
        geometry = geometry_reference.Clone()
        geometry.Transform(transformation)
        target_feature.SetGeometryDirectly(geometry)
        
    return target_feature

    
def convert_datasource(source_datasource, target_format_name, output_destination, 
                       source_epsg_id, target_epsg_id=None, bbox=None):
    """
    source_datasource: ogr datasource
    target_format_name: string
    output_destination: string
    source_epsg_id: int
    target_epsg_id: int
    bbox: WKT Polygon
    """
    source_srs = create_srs_from_id(source_epsg_id)
    
    # KML will always be WGS84, avoid double transformation
    transformation = None
    if target_epsg_id is not None and target_format_name != 'KML':
        target_srs = create_srs_from_id(target_epsg_id)
        transformation = osr.CoordinateTransformation(source_srs, target_srs)
    
    # create target datasource
    target_driver = driver_by_name(target_format_name)
    target_datasource = create_datasource(target_driver, output_destination)

    for layer in iterate_layers(source_datasource):
            
        if bbox is not None:
            bbox_geometry = ogr.CreateGeometryFromWkt(bbox)
            layer.SetSpatialFilter(bbox_geometry)
            
        name = layer.GetName()
        if 'ogdwien' in name:
            layer_name_new= "ogdwien_"+name[8:-3].lower()
            print layer_name_new, layer.GetFeatureCount()
            
            target_layer = create_layer(layer,layer_name_new,source_srs, target_datasource)
            target_feature_definition = target_layer.GetLayerDefn()
            
            for feature in iterate_features(layer):
                target_feature = create_feature(feature, target_feature_definition, 
                                                transformation)
                target_layer.CreateFeature(target_feature)
    
    target_datasource.Release()


def main():
    
    src_path = 'WFS:http://data.wien.gv.at/daten/wfs?&srsName=EPSG:4326'
    src_driver = driver_by_name('WFS')
    src_datasource = open_datasource(src_driver, src_path, False)
   
     source_srs = create_srs_from_id(source_epsg_id)
    
    # KML will always be WGS84, avoid double transformation
    transformation = None
    if target_epsg_id is not None and target_format_name != 'KML':
        target_srs = create_srs_from_id(target_epsg_id)
        transformation = osr.CoordinateTransformation(source_srs, target_srs)
    
    # create target datasource
    target_driver = driver_by_name(target_format_name)
    target_datasource = create_datasource(target_driver, output_destination)

    for layer in iterate_layers(source_datasource):
            
        if bbox is not None:
            bbox_geometry = ogr.CreateGeometryFromWkt(bbox)
            layer.SetSpatialFilter(bbox_geometry)
            
        name = layer.GetName()
        if 'ogdwien' in name:
            layer_name_new= "ogdwien_"+name[8:-3].lower()
            print layer_name_new, layer.GetFeatureCount()
            
            target_layer = create_layer(layer,layer_name_new,source_srs, target_datasource)
            target_feature_definition = target_layer.GetLayerDefn()
            
            for feature in iterate_features(layer):
                target_feature = create_feature(feature, target_feature_definition, 
                                                transformation)
                target_layer.CreateFeature(target_feature)
    
    target_datasource.Release()0])
    
    #output_path = "odgtestwfs4.kml"
    #convert_datasource(src_datasource, 'KML', output_path, 4326, None, None)
                               
    src_datasource.Release()
    
    
if __name__ == '__main__':
    main()
